(ns dbutils
 (:use clojure.contrib.sql)
 (:use clojure.contrib.str-utils)
 (:use clojure.contrib.sql.internal))

(add-classpath "file:\\F:\\ojdbc14.jar")
(def dbspec
  {:classname "oracle.jdbc.driver.OracleDriver"
   :user "qc"
   :password "w123456"
   :subprotocol "oracle:thin:@192.168.1.9:1521"
   :subname "QCDB"
   })

(def conn (get-connection dbspec))

(def me (.getMetaData conn))
(def schems "QC")

(def filter-name [])

;(def tables  (let [ a  (resultset-seq (. me (getTables nil schems nil nil)))]
    ;          (filter fn [a] (apply or (map #(.contains (a :table_name) %) filter-name))) a))

(defn type2type
  "type of database to java type"
  [t]
  (let [ty (t :type_name)
        di (t :decimal_digits)]
  (cond (and (.contains ty  "NUMBER") (= di 0)) "Long"
        (and (.contains ty  "NUMBER") (not (= di 0))) "Double"
        (or ( .contains ty "TIME") ( .contains ty "DATE")) "Date"
    :else "String")))


(defn column
  "get colums from table tname"
  [tname]
  (loop [kys  (resultset-seq (. me (getColumns nil schems tname nil)))
         rs []]
    (if (seq kys)
      (recur (next kys)
        (cons {:name ((first kys) :column_name ) :type (type2type (first kys) ) } rs
          ))
     (reverse rs))))


(defn pkey
  "get privit key from table"
  [tname]
  (loop [kys (resultset-seq  (. me (getPrimaryKeys nil schems tname)))
         rs []]
    (if (seq kys)
      (recur (next kys)
        (cons {:pkname  ((first kys) :column_name )} rs
          ))
      rs)))
(defn cap
  [#^String s]
  (if s
    (str (char (Character/toUpperCase (. s (charAt 0)))) (subs  s 1 (count s)))
    ""))

(defn d2j
  "name tranfer"
  [dataname]
  (let [ dataname (.toLowerCase dataname)
        up #(if %
              (.toUpperCase %)
              "")
        ]
    (re-gsub #"_(\S)?" #(up ( %  1)) dataname)
    ))

(defn fkey
  [tname]
  (loop [ kys (resultset-seq  (. me (getImportedKeys nil schems tname)))
         rs []]
    (if (seq kys)
      ( recur (next kys)
        (cons  {:pktable_name (:pktable_name (first kys))
                :fkcolumn_name (:fkcolumn_name (first kys))} rs
          ))
      rs
      )
    ))

(defn table-info
  "get table-info"
  [tname]
  (let [;pkeys (pkey tname)
        columns (column tname)
        ; fkeys (fkey tname);
        ]
    {:name tname
     :column columns
     ; :pk pkeys
     ;   :fk fkeys
     }
    ))



(defn java-info
  ""
  [table-info]
  (let [nam (cap (d2j (table-info :name)))
        c (map (fn [a] (update-in a [ :name]  #(if (= % "CLASS") "class_" (d2j %)))) (table-info :column))
        pk (map (fn [a] (update-in a [ :pkname]  #(d2j %)))  (table-info :pk))
        fk  (map (fn [a] (do  (update-in a [ :fkcolumn_name]  #(d2j %))
                           (update-in a [ :pktable_name]  #(cap (d2j %))) ))  (table-info :fk))
        ]
    [ table-info {
                  :name   nam
                  :column  c
                  :pk pk
                  :fk fk
                  }]
    ))



(defn each [f s]
  (doseq [ as s]
    (f as)))


;(defn all
;  []
 ; (doseq [ t tables]
 ;   (println (java-info (table-info (t :table_name))))
  ;  ))


(defn do-tpl
  [s & args ]
  (let [ st (org.antlr.stringtemplate.StringTemplate. s)
        args (partition 2 args)]
    (do (doseq [ a args]
          (.setAttribute st (first a) (second a))
          )
      (str "  "   st))))

(defn namer [a] a)

(defn selsql [t]
  (let [t (first t)
        c (t :column)
        cs (map #(.toLowerCase (str (% :name) " ")) c)
        ps (interpose "," cs )
        ]

    (str (cap (namer (d2j (t :name))))  "Sql = select "  (apply str ps) "from qc." (t :name))))

(def gtpl "public void set$name$($type$ $oname$){
                                                 this.$oname$=$oname$;
                                                 }
    public $type$ get$name$(){
             return this.$oname$;}
")



(defn vo [t]
  (let [t (second t)
        c (t :column)
        na (namer (t :name))
        getter (map #(do-tpl gtpl  "type" (% :type) "oname" (% :name) "name" (cap (% :name))) c)
        ziduan (map #(str "private " (% :type) "  " (% :name) "; \n") c)
        ]

    (str "package "  "; \n import java.util.Date; \n" "public class " na " implements java.io.Serializable{\n " (apply str ziduan) (apply str getter) "}" )))


(def path "C:\\Documents and Settings\\Administrator\\My Documents\\NetBeansProjects\\ClojureAS\\")

(defn vofile [a](
   ((let [ t  (java-info (table-info a))
           f (new java.io.File (str path a ".java"))
           fw (new java.io.FileWriter f )
        ;  fw (if (.exists fw) (do (.delete fw) (new java.io.FileWriter f )) fw )
          ]
         (do (println  f)
              (println (.getAbsolutePath f))
              (.write fw (vo t))
              (.close fw))))
     ))


